﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Windows.Forms;
using System.Xml;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.IO;
using System.ComponentModel;

namespace TweetMyApps
{
    public class AppInfo : IComparable<AppInfo>
    {
        public const string OTHERS_CATEGORY_NAME = "Others";

        private string _shortName;
        private string _fileName;
        private string _titlePattern;
        private string _name;
        private string _category = OTHERS_CATEGORY_NAME;
        private bool _monitored = true;

        [DisplayName("Filename"), Category("Detection"), Description("FileName of the application")]
        public string FileName { get { return _fileName; } set { _fileName = value; } }

        [DisplayName("TitlePattern"), Category("Detection"), Description(
@"TitlePattern
Application : [*]Title[*]
MDI Application : [*-][*]Title[*]
Document : [*]Title[*][-*]")]
        public string TitlePattern { get { return _titlePattern; } set { _titlePattern = value; } }

        [DisplayName("Monitored"), Category("Detection"), Description("Indicates if this application usage should be monitored")]
        public bool Monitored { get { return _monitored; } set { _monitored = value; } }

        [DisplayName("Shortname"), Category("Informations"), Description("Very short name of the application (used for Tweet)")]
        public string ShortName { get { return _shortName; } set { _shortName = value; } }

        [DisplayName("Display Name"), Category("Informations"), Description("Display Name of the application")]
        public string Name { get { return _name; } set { _name = value; } }

        [DisplayName("Category"), Category("Informations"), Description("Indicates the category in which this application should be filled")]
        public string Category { get { return _category; } set { _category = value; } }

        public string CurrentTitle;
        public int Usage;

        public override string ToString()
        {
            return Name;
        }

        public AppInfo()
        {
        }
        public AppInfo(string appInfoLine)
        {
            string[] splits = appInfoLine.Split(';');
            int idx = 0;
            this.FileName = splits[idx++].ToLower();
            this.TitlePattern = splits[idx++].ToLower();
            this.Name = splits[idx++];
            this.ShortName = splits[idx++];
            this.Category = splits[idx++];

            if (splits.Length > idx && !string.IsNullOrEmpty(splits[idx]))
                if (Int32.TryParse(splits[idx], out this.Usage))
                    idx++;
            this.Monitored = !(splits.Length > idx && !string.IsNullOrEmpty(splits[idx]));
        }

        public string Serialize()
        {
            string appInfoLine = string.Join(";",
                new string[]
					{
						this.FileName,
						this.TitlePattern,
						this.Name,
						this.ShortName,
						this.Category,
						this.Usage.ToString(),
						this.Monitored ? string.Empty : "-"
					});
            return appInfoLine;
        }

        #region IComparable<AppInfo> Members

        public int CompareTo(AppInfo other)
        {
            if (other == null) return -1;
            int cmp = this.Category.CompareTo(other.Category);
            if (cmp == 0)
                cmp = this.Name.CompareTo(other.Name);
            return cmp;
        }

        #endregion

        public override int GetHashCode()
        {
            return FileName.GetHashCode() 
                | TitlePattern.GetHashCode() 
                | Name.GetHashCode()
                | ShortName.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            AppInfo other = null;
            other = obj as AppInfo;
            if (other == null) return false;
            return FileName.Equals(other.FileName)
                && TitlePattern.Equals(other.TitlePattern)
                && Name.Equals(other.Name)
                && ShortName.Equals(other.ShortName);
        }
    }
    public class AppInfoComparer : IComparer<AppInfo>, IComparer
    {
        #region IComparer<AppInfo> Members

        public int Compare(AppInfo x, AppInfo y)
        {
            if (x == null && y == null) return 0;
            if (x == null) return 1;
            return x.CompareTo(y);
        }

        #endregion

        #region IComparer Members

        public int Compare(object x, object y)
        {
            if (x is ListViewItem && ((ListViewItem)x).Tag is AppInfo
                && y is ListViewItem && ((ListViewItem)y).Tag is AppInfo)
                return Compare((AppInfo)((ListViewItem)x).Tag, (AppInfo)((ListViewItem)y).Tag);
            if (!(x is AppInfo) && !(y is AppInfo))
                return 0;
            if (!(x is AppInfo)) return 1;
            if (!(y is AppInfo)) return -1;
            return Compare((AppInfo)x, (AppInfo)y);
        }

        #endregion
    }

    public class AppInfos : List<AppInfo>
    {
        private bool WildCardMatch(string pattern, string text)
        {
            if (pattern == text)
                return true;
            if (pattern == "*")
                return true;
            if (pattern.StartsWith("*")
                && pattern.EndsWith("*")
                && text.Contains(pattern.Trim('*')))
                return true;
            if (pattern.StartsWith("*")
                && text.EndsWith(pattern.TrimStart('*')))
                return true;
            if (pattern.EndsWith("*")
                && text.StartsWith(pattern.TrimEnd('*')))
                return true;
            return false;
        }

        public void Save(string dbPath)
        {
            List<string> db = new List<string>();
            foreach (AppInfo appInfo in this)
            {
                db.Add(appInfo.Serialize());
            }
            File.WriteAllLines(dbPath, db.ToArray());
        }


        public void Load(string dbPath)
        {
            if (File.Exists(dbPath))
            {
                string[] appInfosDB = File.ReadAllLines(dbPath);
                this.Clear();
                foreach (string appInfoLine in appInfosDB)
                {
                    if (string.IsNullOrEmpty(appInfoLine.Trim())
                        || appInfoLine.StartsWith("//"))
                        continue;
                    AppInfo appInfo = new AppInfo(appInfoLine);
                    this.Add(appInfo);
                }
            }
        }
        public void Merge(AppInfos appInfos)
        {
            foreach (AppInfo appInfo in appInfos)
            {
                if (!this.Contains(appInfo))
                    this.Add(appInfo);
            }
        }

        public AppInfo GetAppInfo(string appName, string fileName)
        {
            List<AppInfo> candidates = new List<AppInfo>();
            List<AppInfo> winnersExact = new List<AppInfo>();
            List<AppInfo> winnersApp = new List<AppInfo>();
            List<AppInfo> winnersDoc = new List<AppInfo>();
            string docName = appName;
            if (string.IsNullOrEmpty(fileName)
                || fileName == "idle"
                || fileName == "Unknown"
				|| appName == "Unknown")
                return null;
            if (appName.Contains(" - "))
                docName = appName.Substring(0, appName.LastIndexOf(" - ")).ToLower();
            foreach (AppInfo appInfo in this)
            {
                if (WildCardMatch(appInfo.FileName, fileName))
                    candidates.Add(appInfo);
            }
            foreach (AppInfo appInfo in candidates)
            {
                // Title is optional
                if (string.IsNullOrEmpty(appInfo.TitlePattern))
                    winnersApp.Add(appInfo);
                // Title must contain Document
                else if (appInfo.TitlePattern == "*-")
                {
                    foreach (AppInfo docInfo in candidates)
                    {
                        if (!string.IsNullOrEmpty(docInfo.TitlePattern) && docInfo.TitlePattern.EndsWith("-*"))
                            if (WildCardMatch(docInfo.TitlePattern.Remove(docInfo.TitlePattern.Length - 2), docName))
                                winnersDoc.Add(docInfo);
                    }
                    winnersApp.Add(appInfo);
                }
                // Title matches
                else if (WildCardMatch(appInfo.TitlePattern, appName))
                    winnersExact.Add(appInfo);
            }
            if (winnersDoc.Count > 0)
            {
                winnersDoc[0].CurrentTitle = appName;
                return winnersDoc[0];
            }
            if (winnersApp.Count > 0)
            {
                winnersApp[0].CurrentTitle = appName;
                return winnersApp[0];
            }
            if (winnersExact.Count > 0)
            {
                winnersExact[0].CurrentTitle = appName;
                return winnersExact[0];
            }
            AppInfo newAppInfo = new AppInfo();
            newAppInfo.ShortName = appName.Substring(0,
                                                          (appName.Length > 25 && appName.IndexOf(' ', 25) > 0)
                                                            ? appName.IndexOf(' ', 25) + 1
                                                            : appName.Length);
            newAppInfo.Name = appName;
            newAppInfo.CurrentTitle = appName;
            newAppInfo.TitlePattern = "";
            newAppInfo.FileName = fileName;
            newAppInfo.Category = AppInfo.OTHERS_CATEGORY_NAME;
            this.Add(newAppInfo);
            return newAppInfo;
        }

        public void ResetAllUsage()
        {
            foreach (AppInfo appInfo in this)
            {
                appInfo.Usage = 0;
            }
        }
    }

}

